package com.dhms.vostok1.network

import android.util.Log
import com.dhms.vostok1.constant.ErrorCode
import com.dhms.vostok1.data.ApiException
import com.dhms.vostok1.data.BaseResData
import com.squareup.moshi.JsonDataException
import com.squareup.moshi.JsonEncodingException
import okhttp3.OkHttpClient
import org.json.JSONException
import org.json.JSONObject
import retrofit2.Converter
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import java.lang.reflect.ParameterizedType
import java.util.concurrent.TimeUnit

/**
 * 网络请求封装
 */
abstract class BaseNetworkApi<I : Any> {
    private val retrofitBuilder = Retrofit.Builder()
        .addConverterFactory(initFactory())
        .client(defaultOkHttpClient)

    /**
     * retrofit object using a Moshi converter
     */
    private lateinit var retrofit: Retrofit

    protected lateinit var service: I

    var baseUrl: String? = null
        private set

    val wsUrl: String?
        get() {
            return baseUrl?.replace("http://", "ws://")?.replace("https://", "wss://")
        }

    /**
     * 重写此方法设置对应的Factory
     */
    abstract fun initFactory(): Converter.Factory

    fun initNetwork(url: String) {
        Log.i(TAG, "initNetwork: $url")
        retrofit = retrofitBuilder.baseUrl(url).build()
        service = retrofit.create(getServiceClass())
        baseUrl = url
    }

    @Suppress("UNCHECKED_CAST")
    private fun getServiceClass(): Class<I> {
        val genType = javaClass.genericSuperclass as ParameterizedType
        return genType.actualTypeArguments[0] as Class<I>
    }

    protected suspend fun <T> getResult(block: suspend () -> Response<BaseResData<T>>): Result<Response<BaseResData<T>>?> {
        var code = -1
        var message: String? = null
        var res: Response<BaseResData<T>>? = null
        try {
            res = block()
            code = res.code()
            message = res.body().toString()
            val resBody = res.body()
            code = (resBody?.status)?.toInt() ?: code
            if (code != ErrorCode.OK) {
                message = resBody?.message ?: res.message()
                if (res.errorBody() != null) {
                    val jsonObj = res.errorBody()?.charStream()?.readText()?.let { JSONObject(it) }
                    if (jsonObj?.isNull("message") == false) {
                        message = jsonObj.getString("message")
                    }
                }
                throw ApiException(
                    code,
                    message ?: "请求返回出错"
                )
            }
            return Result.success(res)
        } catch (e: Exception) {
            Log.e(
                TAG,
                "A error occurred with http info $res and message ${e.message}",
                e
            )
            return when (e) {
                is JsonDataException -> Result.failure(ApiException(code, "数据格式有误，请联系管理员！"))
                is JsonEncodingException -> Result.failure(ApiException(code, "数据格式有误，请联系管理员！"))
                is JSONException -> Result.failure(ApiException(code, "数据格式有误，请联系管理员！"))
                else -> Result.failure(ApiException(code, e.message ?: message))
            }
        }
    }

    companion object {
        const val TAG = "Network"

        private val defaultOkHttpClient by lazy {
            val builder = OkHttpClient.Builder()
                .callTimeout(15L, TimeUnit.SECONDS)
                .connectTimeout(15L, TimeUnit.SECONDS)
                .readTimeout(15L, TimeUnit.SECONDS)
                .writeTimeout(15L, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)

            builder.addInterceptor(RequestInterceptor())
            builder.addInterceptor(ResponseInterceptor())

          /* if (BuildConfig.DEBUG) {
                val loggingInterceptor = HttpLoggingInterceptor()
                loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
                builder.addInterceptor(loggingInterceptor)
           }*/

            builder.build()
        }
    }

}